﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using NLog;

namespace LB.Server.Common
{
    public class ApplicationLog
    {
        private static string BaseNamespace = "LB.Server.Common";
        protected readonly Logger Log;

        #region Constructors

        public ApplicationLog()
        {
            var callerName = GetFullMethodName();
            Log = LogManager.GetLogger(callerName.Substring(0, callerName.LastIndexOf(".")));
        }

        public ApplicationLog(string loggerName)
        {
            Log = LogManager.GetLogger(loggerName);
        }

        public ApplicationLog(string loggerName, string baseNamespace)
        {
            BaseNamespace = baseNamespace;
            Log = LogManager.GetLogger(loggerName);
        }

        #endregion

        #region Public Write Methods

        public void WriteTrace(String logMessage)
        {
            if (!Log.IsDebugEnabled) return;
            Log.Debug("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteTrace(String logMessage, Exception exp)
        {
            if (!Log.IsDebugEnabled) return;
            Log.Debug("[" + GetMethodName() + "] " + logMessage, exp);
        }

        public void WriteTrace(String logMessage, params object[] args)
        {
            if (!Log.IsDebugEnabled) return;
            logMessage = String.Format(CultureInfo.InvariantCulture, logMessage, args);
            Log.Debug("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteInfo(String logMessage)
        {
            if (!Log.IsInfoEnabled) return;
            Log.Info("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteInfo(String logMessage, Exception exp)
        {
            if (!Log.IsInfoEnabled) return;
            Log.Info("[" + GetMethodName() + "] " + logMessage, exp);
        }

        public void WriteInfo(String logMessage, params object[] args)
        {
            if (!Log.IsInfoEnabled) return;
            logMessage = String.Format(CultureInfo.InvariantCulture, logMessage, args);
            Log.Info("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteWarning(String logMessage)
        {
            if (!Log.IsWarnEnabled) return;
            Log.Warn("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteWarning(String logMessage, Exception exp)
        {
            if (!Log.IsWarnEnabled) return;
            Log.Warn("[" + GetMethodName() + "] " + logMessage, exp);
        }

        public void WriteWarning(String logMessage, params object[] args)
        {
            if (!Log.IsWarnEnabled) return;
            logMessage = String.Format(CultureInfo.InvariantCulture, logMessage, args);
            Log.Warn("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteError(String logMessage)
        {
            if (!Log.IsErrorEnabled) return;
            Log.Error("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteError(String logMessage, Exception exp)
        {
            if (!Log.IsErrorEnabled) return;
            Log.Error("[{0}] {1} - {2} \nInnerException - {3}", GetMethodName(), logMessage, exp.Message, exp.InnerException);
        }

        public void WriteError(String logMessage, params object[] args)
        {
            if (!Log.IsErrorEnabled) return;
            logMessage = String.Format(CultureInfo.InvariantCulture, logMessage, args);
            Log.Error("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteFatal(String logMessage)
        {
            if (!Log.IsFatalEnabled) return;
            Log.Fatal("[" + GetMethodName() + "] " + logMessage);
        }

        public void WriteFatal(String logMessage, Exception exp)
        {
            if (!Log.IsFatalEnabled) return;
            Log.Fatal("[{0}] {1} \nInnerException - {2}", GetMethodName(), logMessage, exp.Message, exp.InnerException);
        }

        public void WriteFatal(String logMessage, params object[] args)
        {
            if (!Log.IsFatalEnabled) return;
            logMessage = String.Format(CultureInfo.InvariantCulture, logMessage, args);
            Log.Fatal("[" + GetMethodName() + "] " + logMessage);
        }

        #endregion

        #region Private Methods

        private static MethodBase GetMethodBase()
        {
            var stackTrace = new StackTrace();
            StackFrame stackFrame;
            MethodBase stackFrameMethod;

            var frameCount = 0;
            do
            {
                frameCount++;
                stackFrame = stackTrace.GetFrame(frameCount);
                stackFrameMethod = stackFrame.GetMethod();
            } while (stackFrameMethod.ReflectedType.FullName.StartsWith(BaseNamespace));

            return stackFrame.GetMethod();
        }

        private static string GetFullMethodName()
        {
            var callerMethodBase = GetMethodBase();
            return callerMethodBase.ReflectedType.FullName + "." + callerMethodBase.Name;
        }

        private static string GetMethodName()
        {
            var callerMethodBase = GetMethodBase();
            return callerMethodBase.ReflectedType.Name + "." + callerMethodBase.Name;
        }

        #endregion
    }
}